package avicit.bdp.dms.das.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.service.dto.BdpColumnDTO;
import avicit.bdp.common.service.dto.BdpTableDTO;
import avicit.bdp.common.service.service.DataQueryService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.common.utils.ConfigUtils;
import avicit.bdp.common.utils.DateUtils;
import avicit.bdp.common.utils.enums.CommonTypeEnums;
import avicit.bdp.core.constant.Constants;
import avicit.bdp.core.file.util.FileUtils;
import avicit.bdp.core.poi.util.csv.ExcelUtils;
import avicit.bdp.core.poi.util.csv.style.ExcelExportTitleStyle;
import avicit.bdp.dms.das.dao.BdpDasStatDao;
import avicit.bdp.dms.das.dto.BdpDasStatDTO;
import avicit.bdp.dms.perm.utils.common.PermCommonService;
import avicit.platform6.core.context.ThreadContextHelper;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.properties.PlatformConstant;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * @author xugb
 */
@Service
public class BdpDasStatService extends BaseService<BdpDasStatDao, BdpDasStatDTO> {

    @Autowired
    private BdpDasTableService bdpDasTableService;

    @Autowired
    private BdpDasColumnService bdpDasColumnService;

    @Autowired
    private DataQueryService dataQueryService;

    @Autowired
    private PermCommonService commonService;

    public Map<String, Object> searchFirstData(Map<String, Object> queryMap) {
        Map<String, Object> map = Maps.newHashMap();
        //昨天的数据==总的数据
        String yesterday = DateUtils.getDayNumBeforeToday(1);
        BdpDasStatDTO stat = this.mapper.selectStat();
        Long lakeDataCount = 0L;
        if (stat != null) {
            lakeDataCount = stat.getLakeDataCount();
        } else {
            stat = new BdpDasStatDTO();
            stat.setLakeDataCount(lakeDataCount);
        }
        String unit = FileUtils.formatNumber(lakeDataCount);
        Double lakeDate = FileUtils.formatAmountUnit(unit, lakeDataCount);
        String lakeDateCountStr = lakeDate + unit;
        stat.setLakeDataCountStr(lakeDateCountStr);
        map.put("stat", stat);

        // 所选表类型--第一次进入为日统计
        //开始时间
        String startDate;
        //结束时间
        String endDate;
        //存放日期数据
        List<String> dateList = Lists.newArrayList();
        //模型数量集合
        List<Long> modelCountList = Lists.newArrayList();
        //数据湖数量集合
        List<Long> lakeTableCountList = Lists.newArrayList();
        //数据湖容量集合
        List<Double> amountList = Lists.newArrayList();
        //数据湖容量原始集合
        List<Long> amountListTemp = Lists.newArrayList();
        //右轴单位
        String amountUnit = "";
        String statType = MapUtils.getString(queryMap, "statType", "0");

        //按周查询
        if ("0".equals(statType)) {
            startDate = DateUtils.getCurrentMonday(null);
            dateList.add(startDate.substring(startDate.indexOf("-") + 1));

            String afterDay = DateUtils.getDayAfterToday(startDate, 1, Constants.YYYY_MM_DD);
            for (int i = 0; i < 6; i++) {
                dateList.add(afterDay.substring(startDate.indexOf("-") + 1));
                afterDay = DateUtils.getDayAfterToday(afterDay, 1, Constants.YYYY_MM_DD);
            }

            endDate = yesterday;
            List<BdpDasStatDTO> weekList = this.mapper.selectByWeek(startDate, endDate);
            if (CollectionUtils.isNotEmpty(weekList)) {
                Map<String, BdpDasStatDTO> weekDataMap = Maps.newHashMap();
                for (BdpDasStatDTO dasStatDTO : weekList) {
                    weekDataMap.put(dasStatDTO.getStatisticsDate().substring(5), dasStatDTO);
                    amountListTemp.add(dasStatDTO.getLakeDataCount());
                }
                Long maxAmount = 0L;
                //获取最小值
                if (CollectionUtils.isNotEmpty(amountListTemp)) {
                    maxAmount = Collections.max(amountListTemp);
                }
                // 右轴单位
                amountUnit = FileUtils.formatNumber(maxAmount);
                dataHandle(amountUnit, modelCountList, lakeTableCountList, amountList, weekDataMap, dateList);
            } else {
                //赋null值
                nullHandle(modelCountList, lakeTableCountList, amountList, 7);
            }
        } else if ("1".equals(statType)) {
            // 获取当天月份
            String currentMonth = DateUtils.getCurrentMonth();
            //获取当前年份
            int year = Integer.parseInt(currentMonth.substring(0, 4));
            int month = Integer.parseInt(currentMonth.substring(currentMonth.length() - 2));
            //获取当月天数
            int days = DateUtils.getDays(year, month);
            for (int i = 1; i <= days; i++) {
                dateList.add(i + "日");
            }
            List<BdpDasStatDTO> monthList = this.mapper.selectByMonth(currentMonth);
            if (monthList != null && monthList.size() > 0) {
                Map<String, BdpDasStatDTO> monthDataMap = Maps.newHashMap();
                for (BdpDasStatDTO dasStatDTO : monthList) {
                    String key = Integer.parseInt(dasStatDTO.getStatisticsDate().substring(dasStatDTO.getStatisticsDate().length() - 2)) + "日";
                    monthDataMap.put(key, dasStatDTO);
                    amountListTemp.add(dasStatDTO.getLakeDataCount());
                }
                Long maxAmount = 0L;
                //获取最小值
                if (CollectionUtils.isNotEmpty(amountListTemp)) {
                    maxAmount = Collections.max(amountListTemp);
                }
                // 右轴单位
                amountUnit = FileUtils.formatNumber(maxAmount);
                dataHandle(amountUnit, modelCountList, lakeTableCountList, amountList, monthDataMap, dateList);
            } else {
                //赋null值
                nullHandle(modelCountList, lakeTableCountList, amountList, days);
            }
        } else if ("2".equals(statType)) {
            String year = DateUtils.year().toString();
            for (int i = 1; i <= 12; i++) {
                dateList.add(i + "月");
            }

            List<Map<String, Object>> yearList = this.mapper.selectByYear(year);
            if (yearList != null && yearList.size() > 0) {
                Map yearDataMap = Maps.newHashMap();
                for (Map<String, Object> dataMap : yearList) {
                    String key = Integer.parseInt(((String) dataMap.get("statisticsDate"))
                            .substring(((String) dataMap.get("statisticsDate")).length() - 2)) + "月";
                    yearDataMap.put(key, dataMap);
                    amountListTemp.add(Long.parseLong(dataMap.get("lakeDataCount").toString()));
                }

                Long maxAmount = 0L;
                //获取最小值
                if (CollectionUtils.isNotEmpty(amountListTemp)) {
                    maxAmount = Collections.max(amountListTemp);
                }

                // 右轴单位
                amountUnit = FileUtils.formatNumber(maxAmount);
                //dataHandle(amountUnit, modelCountList, lakeTableCountList, amountList, yearDataMap, dateList);

                if (CollectionUtils.isNotEmpty(dateList)) {
                    for (String dateKey : dateList) {
                        if (yearDataMap.containsKey(dateKey)) {
                            Map<String, Object> dto = (Map<String, Object>) yearDataMap.get(dateKey);
                            modelCountList.add(Long.parseLong(dto.get("modelCount").toString()));
                            lakeTableCountList.add(Long.parseLong(dto.get("lakeTableCount").toString()));
                            amountList.add(FileUtils.formatAmountUnit(amountUnit,
                                    Long.parseLong(dto.get("lakeDataCount").toString())));
                        } else {
                            modelCountList.add(null);
                            lakeTableCountList.add(null);
                            amountList.add(null);
                        }
                    }
                }
            } else {
                //赋null值
                nullHandle(modelCountList, lakeTableCountList, amountList, 12);
            }
        }

        map.put("statType", statType);
        map.put("amountUnit", amountUnit);
        map.put("dateList", dateList);
        map.put("modelCountList", modelCountList);
        map.put("lakeTableCountList", lakeTableCountList);
        map.put("amountList", amountList);

        return map;
    }

    private void nullHandle(List<Long> modelCountList, List<Long> lakeTableCountList,
                            List<Double> amountList, int count) {
        for (int i = 0; i < count; i++) {
            modelCountList.add(null);
            lakeTableCountList.add(null);
            amountList.add(null);
        }
    }

    private void dataHandle(String amountUnit, List<Long> modelCountList,
                            List<Long> lakeTableCountList, List<Double> amountList,
                            Map<String, BdpDasStatDTO> statMap, List<String> dateList) {
        //循坏日期list，对应存放数据
        if (dateList != null && dateList.size() > 0) {
            for (String dateKey : dateList) {
                if (statMap.containsKey(dateKey)) {
                    BdpDasStatDTO dto = statMap.get(dateKey);
                    modelCountList.add(dto.getModelCount());
                    lakeTableCountList.add(dto.getLakeTableCount());
                    amountList.add(FileUtils.formatAmountUnit(amountUnit, dto.getLakeDataCount()));
                } else {
                    modelCountList.add(null);
                    lakeTableCountList.add(null);
                    amountList.add(null);
                }
            }
        }
    }


    public boolean isRun() {
        String yesterday = DateUtils.getDayNumBeforeToday(1);
        BdpDasStatDTO bdpDasStatDTO = new BdpDasStatDTO();
        bdpDasStatDTO.setStatisticsDate(yesterday);
        List<BdpDasStatDTO> list = this.selectList(bdpDasStatDTO);
        return CollectionUtils.isNotEmpty(list);
    }


    /**
     * 查询数据库表的数据
     *
     * @return 数据库表数据
     */
    public Map<String, Object> getDataListByTable(Map<String, Object> queryMap) {

        String tableId = MapUtils.getString(queryMap, "tableId");
        String paramJson = MapUtils.getString(queryMap, "paramJson");
        Integer pageNum = MapUtils.getInteger(queryMap, "pageNum");
        Integer pageSize = MapUtils.getInteger(queryMap, "pageSize");
        BdpTableDTO tableDTO = bdpDasTableService.selectByPrimaryKey(tableId);
        if (tableDTO == null) {
            return Maps.newHashMap();
        }

        BdpColumnDTO columnQuery = new BdpColumnDTO();
        columnQuery.setTableId(tableId);
        List<BdpColumnDTO> columnList = bdpDasColumnService.selectList(columnQuery);
        tableDTO.setColumnList(columnList);

        String querySql = this.commonService.splicingSelectSql(tableDTO, paramJson, isHaveSecretLevelWord(columnList));
        if (querySql == null) {
            return new HashMap<>(16);
        }

        Map<String, Object> map = dataQueryService.getDataListByTable(tableDTO, null, querySql, null, pageNum, pageSize);
        String logTitle = "查看表：【" + tableDTO.getName() + "】的数据";
        BdpLogUtil.log("数据查看模块", logTitle, PlatformConstant.OpType.select);
        return map;
    }

    /**
     * 对外接口，根据模型表ID、列名称获取指定列的数据（默认返回前100个）
     *
     * @param tableId 模型表ID
     * @param colName 列名称
     * @param limit   条数限制；默认前100条
     * @return
     */
    public List<String> getColumnDataByTableId(String tableId, String colName, Integer limit) {
        // step1:合法性检查
        if (StringUtils.isEmpty(tableId) || StringUtils.isEmpty(colName)) {
            return Collections.EMPTY_LIST;
        }

        BdpTableDTO tableDTO = bdpDasTableService.selectByPrimaryKey(tableId);
        if (tableDTO == null) {
            return Collections.EMPTY_LIST;
        }

        // step2:处理列字段信息
        BdpColumnDTO currBdpColDto = null;
        BdpColumnDTO columnQuery = new BdpColumnDTO();
        columnQuery.setTableId(tableId);
        List<BdpColumnDTO> columnList = bdpDasColumnService.selectList(columnQuery);
        for (BdpColumnDTO bdpColumnDTO : columnList) {
            if (bdpColumnDTO.getName().equals(colName)) {
                currBdpColDto = bdpColumnDTO;
                break;
            }
        }
        // 字段名未找到，返回空集合
        if (currBdpColDto == null) {
            return Collections.EMPTY_LIST;
        }
        columnList.clear();
        columnList.add(currBdpColDto);

        // step3:获取指定列数据
        tableDTO.setColumnList(columnList);
        Map<String, Object> result = dataQueryService.getDataListByTable(
                tableDTO, null, null, null, 1, limit);

        // step4:后处理，仅返回数据
        Set<String> colDatas = new HashSet<>();
        ArrayList<HashMap<String, Object>> resultList = (ArrayList<HashMap<String, Object>>) result.get("resultList");
        if (resultList == null || resultList.isEmpty()) {
            return new ArrayList<>();
        }
        for (HashMap<String, Object> rowData : resultList) {
            colDatas.add(rowData.get(colName).toString());
        }

        return new ArrayList<>(colDatas);
    }

    /**
     * 模型表中是否有secret_level密级字段
     * 注意：数据查询SQL生成方式
     * 1、模型表中有密级字段，场景1：开启密级控制；场景2：未开启密级控制；
     * 2、模型表中没有密级字段，场景1：开启密级空盒子；场景2：未开启密级控制；
     *
     * @param columnList
     * @return true:有密级字段；false:没有密级字段
     */
    private boolean isHaveSecretLevelWord(List<BdpColumnDTO> columnList) {
        String secretLevelWord = ConfigUtils.getInstance().getString(Constants.SECRET_LEVEL_WORD, Constants.SECRET_LEVEL);

        for (BdpColumnDTO columnDTO : columnList) {
            if (columnDTO == null || StringUtils.isEmpty(columnDTO.getName())) {
                continue;
            }

            if (columnDTO.getName().equals(secretLevelWord)) {
                return true;
            }
        }

        return false;
    }

    public void export(Map<String, Object> queryMap, HttpServletResponse response) {
        ExcelUtils excelUtils = new ExcelUtils();

        try {
            Map<String, Object> dataMap = this.getDataListByTable(queryMap);

            List<BdpColumnDTO> columnList = (List<BdpColumnDTO>) dataMap.get("columnList");
            //表头的集合，用于添加表头
            List<ExcelExportEntity> entityList = new ArrayList<>();
            for (BdpColumnDTO column : columnList) {
                String cellTitle = column.getCnName();
                if (StringUtils.isBlank(cellTitle)) {
                    cellTitle = column.getName();
                }
                //列头由参数汉字名称,参数key为列key
                entityList.add(new ExcelExportEntity(cellTitle, column.getName(), 30));
            }

            List<Map<String, Object>> dataList = (List<Map<String, Object>>) dataMap.get("resultList");

            BdpTableDTO modelInfo = (BdpTableDTO) dataMap.get("modelInfo");
            //excel显示表名称
            String tableName = modelInfo.getCnName();
            if(StringUtils.isBlank(tableName)){
                tableName = modelInfo.getName();
            }
            Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(tableName,
                    tableName), entityList, dataList);
            excelUtils.downLoadExcel(modelInfo.getName(), workbook, response);
        } catch (Exception e) {
            if (e.getCause().getMessage().startsWith("The maximum length of cell")) {
                throw new BusinessException("字符长度超出Excel单元格的最大限制，请检查！");
            } else {
                throw new BusinessException(e.getMessage());
            }
        }
    }
}
